package com.test.mylotterysystem.service.Impl;

import com.test.mylotterysystem.comment.errorCode.ServiceErrorCode;
import com.test.mylotterysystem.comment.exception.ServiceException;
import com.test.mylotterysystem.comment.utils.JacksonUtil;
import com.test.mylotterysystem.comment.utils.RedisUtil;
import com.test.mylotterysystem.controller.Param.ActivityCreateParam;
import com.test.mylotterysystem.controller.Param.ActivityCreatePrize;
import com.test.mylotterysystem.controller.Param.ActivityCreateUser;
import com.test.mylotterysystem.controller.Param.PageParam;
import com.test.mylotterysystem.controller.Result.ActivityListResultDTO;
import com.test.mylotterysystem.dao.DO.ActivityDO;
import com.test.mylotterysystem.dao.DO.ActivityPrizeDO;
import com.test.mylotterysystem.dao.DO.ActivityUserDO;
import com.test.mylotterysystem.dao.DO.PrizeDO;
import com.test.mylotterysystem.dao.Mapper.*;
import com.test.mylotterysystem.service.ActivityService;
import com.test.mylotterysystem.service.DTO.ActivityCreateResultDTO;
import com.test.mylotterysystem.service.DTO.ActivityDetailDTO;
import com.test.mylotterysystem.service.DTO.ActivityResultDTO;
import com.test.mylotterysystem.service.serviceEnum.ActivityPrizeStatusEnum;
import com.test.mylotterysystem.service.serviceEnum.ActivityPrizeTiersEnum;
import com.test.mylotterysystem.service.serviceEnum.ActivityStatusEnum;
import com.test.mylotterysystem.service.serviceEnum.ActivityUserStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ActivityServiceImpl implements ActivityService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private PrizeMapper prizeMapper;

    @Autowired
    private ActivityMapper activityMapper;

    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;

    @Autowired
    private ActivityUserMapper activityUserMapper;

    @Autowired
    private RedisUtil redisUtil;

    private final String ACTIVITY_PREFIX = "ACTIVITY_";

    /**
     * 创建活动
     *
     * @param activityCreateParam
     * @return
     */
    @Override
    public ActivityCreateResultDTO createActivity(ActivityCreateParam activityCreateParam) {
        // 校验数据
        checkActivityCreateParam(activityCreateParam);

        // 活动表存储
        ActivityDO activityDO = new ActivityDO();
        activityDO.setActivityName(activityCreateParam.getActivityName());
        activityDO.setDescription(activityCreateParam.getDescription());
        activityDO.setStatus(ActivityStatusEnum.PROCEED.name());
        activityMapper.insertActivity(activityDO);


        // 活动奖品表存储
        List<ActivityCreatePrize> activityPrizeList = activityCreateParam.getActivityPrizeList();
        List<ActivityPrizeDO> prizeDOList = activityPrizeList.stream().map(activityCreatePrize -> {
            ActivityPrizeDO activityPrizeDO = new ActivityPrizeDO();
            activityPrizeDO.setActivityId(activityDO.getId());
            activityPrizeDO.setPrizeId(activityCreatePrize.getPrizeId());
            activityPrizeDO.setPrizeAmount(activityCreatePrize.getPrizeAmount());
            activityPrizeDO.setPrizeTiers(activityCreatePrize.getPrizeTiers());
            activityPrizeDO.setStatus(ActivityPrizeStatusEnum.INIT.name());
            return activityPrizeDO;
        }).collect(Collectors.toList());

        activityPrizeMapper.saveActivityPrizeList(prizeDOList);

        // 活动人员表存储
        List<ActivityCreateUser> activityUserList = activityCreateParam.getActivityUserList();
        List<ActivityUserDO> userDOList = activityUserList.stream().map(activityCreateUser -> {
            ActivityUserDO activityUserDO = new ActivityUserDO();
            activityUserDO.setActivityId(activityDO.getId());
            activityUserDO.setUserId(activityCreateUser.getUserId());
            activityUserDO.setUserName(activityCreateUser.getUserName());
            activityUserDO.setStatus(ActivityUserStatusEnum.INIT.name());
            return activityUserDO;
        }).collect(Collectors.toList());

        activityUserMapper.saveActivityUserList(userDOList);

        // 将整合数据存储到redis中
        List<Long> prizesId = activityPrizeList.stream().map(activityCreatePrize -> activityCreatePrize.getPrizeId()).collect(Collectors.toList());
        List<PrizeDO> prizeDOS = prizeMapper.getPrizeListByIds(prizesId);

        ActivityDetailDTO activityDetailDTO = createActivityDetailDTO(activityDO, prizeDOList, userDOList, prizeDOS);

        saveSourceToRedis(activityDetailDTO);

        // 返回值
        ActivityCreateResultDTO activityCreateResultDTO = new ActivityCreateResultDTO(activityDO.getId());
        return activityCreateResultDTO;
    }


    /**
     * 保存整合数据到redis中
     *
     * @param activityDetailDTO
     */
    private void saveSourceToRedis(ActivityDetailDTO activityDetailDTO) {
        if (activityDetailDTO == null) {
            throw new ServiceException(ServiceErrorCode.CREATE_ACTIVITY_DETAIL_IS_ERROR);
        }
        try {
            redisUtil.set(ACTIVITY_PREFIX + activityDetailDTO.getActivityId(), JacksonUtil.writeValueAsString(activityDetailDTO));
        } catch (Exception e) {
            log.error("redis存储整合数据时发生异常");
            return;
        }

    }

    /**
     * 创建整合数据对象
     *
     * @param activityDO
     * @param prizeDOList
     * @param userDOList
     * @param prizeDOS
     * @return
     */
    private ActivityDetailDTO createActivityDetailDTO(ActivityDO activityDO, List<ActivityPrizeDO> prizeDOList
            , List<ActivityUserDO> userDOList, List<PrizeDO> prizeDOS) {
        ActivityDetailDTO activityDetailDTO = new ActivityDetailDTO();

        activityDetailDTO.setActivityId(activityDO.getId());
        activityDetailDTO.setActivityName(activityDO.getActivityName());
        activityDetailDTO.setDesc(activityDO.getDescription());
        activityDetailDTO.setStatus(ActivityStatusEnum.PROCEED);

        List<ActivityDetailDTO.PrizeDetailDTO> prizeList = prizeDOList.stream().map(prize -> {
            ActivityDetailDTO.PrizeDetailDTO prizeDetailDTO = new ActivityDetailDTO.PrizeDetailDTO();

            prizeDetailDTO.setPrizeId(prize.getPrizeId());
            prizeDetailDTO.setTiers(ActivityPrizeTiersEnum.forName(prize.getPrizeTiers()));
            prizeDetailDTO.setPrizeAmount(prize.getPrizeAmount());
            prizeDetailDTO.setStatus(ActivityPrizeStatusEnum.forName(prize.getStatus()));

            Optional<PrizeDO> first = prizeDOS.stream().filter(prizeDO -> prizeDO.getId().equals(prize.getPrizeId())).findFirst();
            first.ifPresent(temp -> {
                prizeDetailDTO.setPrizeName(temp.getName());
                prizeDetailDTO.setDescription(temp.getDescription());
                prizeDetailDTO.setPrice(temp.getPrice());
                prizeDetailDTO.setImageUrl(temp.getImageUrl());
            });

            return prizeDetailDTO;
        }).collect(Collectors.toList());

        activityDetailDTO.setPrizeDTOList(prizeList);

        List<ActivityDetailDTO.UserDetailDTO> userList = userDOList.stream().map(user -> {
            ActivityDetailDTO.UserDetailDTO userDetailDTO = new ActivityDetailDTO.UserDetailDTO();
            userDetailDTO.setUserId(user.getUserId());
            userDetailDTO.setUserName(user.getUserName());
            userDetailDTO.setStatus(ActivityUserStatusEnum.forName(user.getStatus()));
            return userDetailDTO;
        }).collect(Collectors.toList());
        activityDetailDTO.setUserDTOList(userList);

        return activityDetailDTO;
    }

    /**
     * 校验活动数据
     *
     * @param activityCreateParam
     */
    private void checkActivityCreateParam(ActivityCreateParam activityCreateParam) {
        // 校验参数不为空
        if (activityCreateParam == null) {
            throw new ServiceException(ServiceErrorCode.ACTIVITY_PARAM_IS_EMPTY);
        }

        // 校验用户是存在的
        List<ActivityCreateUser> activityUserList = activityCreateParam.getActivityUserList();
        List<Long> usersId = activityUserList.stream().map(ActivityCreateUser::getUserId).collect(Collectors.toList());

        List<Long> usersResult = userMapper.selectByUsersId(usersId);

        for (Long userId : usersId) {
            if (!usersResult.contains(userId)) {
                throw new ServiceException(ServiceErrorCode.USER_ID_NOT_EXIST);
            }
        }

        // 校验奖品是存在的
        List<ActivityCreatePrize> activityPrizeList = activityCreateParam.getActivityPrizeList();
        List<Long> prizesId = activityPrizeList.stream().map(ActivityCreatePrize::getPrizeId).collect(Collectors.toList());

        List<Long> prizesResult = prizeMapper.selectByPrizesId(prizesId);

        for (Long prizeId : prizesId) {
            if (!prizesResult.contains(prizeId)) {
                throw new ServiceException(ServiceErrorCode.PRIZE_ID_NOT_EXIST);
            }
        }

        // 校验人员数目大于奖品数目
        long userNumber = usersResult.size();
        long prizeNumber = activityPrizeList.stream().mapToLong(activityCreatePrize -> activityCreatePrize.getPrizeAmount()).sum();
        if (prizeNumber < userNumber) {
            throw new ServiceException(ServiceErrorCode.PRIZE_NUMBER_BIGGER_THAN_USER_NUMBER);
        }
    }

    /**
     * 获取活动列表
     *
     * @param pageParam
     * @return
     */
    @Override
    public ActivityListResultDTO<ActivityResultDTO> getActivityList(PageParam pageParam) {
        ActivityListResultDTO<ActivityResultDTO> resultDTO = new ActivityListResultDTO<>();

        int count = activityMapper.activityCount();
        resultDTO.setTotal(count);

        List<ActivityDO> activityDOS = activityMapper.getActivityList(pageParam.offset(pageParam.getCurrentPage(), pageParam.getPageSize()), pageParam.getPageSize());
        List<ActivityResultDTO> activityResultDTOS = activityDOS.stream().map(activityDO -> {
            ActivityResultDTO activityResultDTO = new ActivityResultDTO();
            activityResultDTO.setActivityId(activityDO.getId());
            activityResultDTO.setActivityName(activityDO.getActivityName());
            activityResultDTO.setDescription(activityDO.getDescription());
            activityResultDTO.setStatus(ActivityStatusEnum.forName(activityDO.getStatus()));
            return activityResultDTO;
        }).collect(Collectors.toList());
        resultDTO.setRecords(activityResultDTOS);

        return resultDTO;
    }
}
